/**
 * 用于拦截和增强数组原生方法的一部分，以便在数组发生变化时能够发出通知。
 * 对于Vue的响应式系统至关重要，它允许Vue追踪数组的变化并更新依赖于这些数组的DOM。
 */
/*
 * 没有进行类型检查，因为Flow类型检查工具在处理动态访问Array原型上的方法时表现不佳。
 * not type checking this file because flow doesn't play well with
 * dynamically accessing methods on Array prototype
 */

import { TriggerOpTypes } from '../../v3'
// 导入def函数，通常用于定义对象的属性，确保属性是响应式的
import { def } from '../util/index'
// 获取数组的原型对象
const arrayProto = Array.prototype
// 创建一个新对象arrayMethods，其原型是Array.prototype
// 这样arrayMethods就可以继承数组的所有原生方法，同时可以在其上定义新的或覆盖原有的方法
export const arrayMethods = Object.create(arrayProto)
//定义一个数组，包含需要被拦截的数组方法名称
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

/**
 * 拦截变化的方法并触发事件
 * Intercept mutating methods and emit events
 */
//遍历methodsToPatch数组，对每个方法名称执行一个函数
methodsToPatch.forEach(function (method) {
  // cache original method
  // 缓存数组原型上对应方法的原始引用，以便稍后调用
  const original = arrayProto[method]
  // 使用def函数在arrayMethods对象上定义一个新方法（或覆盖同名方法）
  // 该方法名为当前遍历到的method，并且接收任意数量的参数（...args）
  // 这个新方法被称为mutator
  def(arrayMethods, method, function mutator(...args) {
    // 调用原始方法，并将this上下文和所有参数传递给它
    // 将结果存储在result变量中
    const result = original.apply(this, args)
    // 尝试从当前操作的数组对象中获取__ob__属性
    // 这个属性是Vue内部使用的，用于存储与该对象关联的Observer实例
    const ob = this.__ob__
    // 声明一个变量inserted，用于后续存储被添加（或插入）的元素
    let inserted
    // 根据调用的方法类型，确定哪些元素被添加到了数组中
    // 对于push和unshift，所有参数都是新添加的元素
    // 对于splice，从第三个参数开始（索引2）的元素是被添加的部分
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    // 如果存在inserted元素，则调用Observer实例的observeArray方法
    // 确保这些新元素也是响应式的
    if (inserted) ob.observeArray(inserted)

      // 通知变更
    // 如果是开发模式，则传递更详细的变更信息
    // notify change
    if (__DEV__) {
      ob.dep.notify({
        type: TriggerOpTypes.ARRAY_MUTATION,// 变更类型
        target: this,// 变更的目标数组
        key: method // 触发变更的方法名
      })
    } else {
      // 如果不是开发模式，则只简单地通知变更
      ob.dep.notify()
    }
    // 返回原始方法的结果
    return result
  })
})
